package com.naiterui.ehp.bs.recommend.service.impl;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.List;

import javax.imageio.ImageIO;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.draw.LineSeparator;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bs.recommend.vo.prescription.PrescriptionInfoVO;
import com.naiterui.ehp.bs.recommend.vo.prescription.PrescriptionSkuVO;

/**
 * @author guoyongxiang
 * @date 2019/9/27 15:43
 * @since 1.0.0
 */
@Service
public class PrescriptionFileMdwkService {

    private static final Logger LOGGER = LoggerFactory.getLogger(PrescriptionFileService.class);

    private static final String HOSPITAL_SEAL_PATH = ConfigUtil.getString("prescription.seal.path");

    private static final int MAX_SKU_QUANTITY = 5;

    BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    BaseFont bfEnglish = BaseFont.createFont(BaseFont.HELVETICA, "", BaseFont.NOT_EMBEDDED);


    Font firsetTitleFont = new Font(bfChinese, 22, Font.BOLD, BaseColor.BLACK); // 一级标题

    Font secondTitleFont = new Font(bfChinese, 15, Font.BOLD, BaseColor.BLACK); // 二级标题

    Font secondTitleFontEn = new Font(bfEnglish, 15, Font.BOLD, BaseColor.BLACK); // 二级标题-EN

    Font fontContent = new Font(bfChinese, 10, Font.NORMAL, BaseColor.BLACK);

    Font fontContent2 = new Font(bfChinese, 9, Font.NORMAL, BaseColor.DARK_GRAY);

    Font fontContentBOLD = new Font(bfChinese, 10, Font.BOLD, BaseColor.BLACK);

    Font fontContentEn = new Font(bfEnglish, 10, Font.NORMAL, BaseColor.BLACK);

    LineSeparator line = new LineSeparator(1f, 100, BaseColor.GRAY, Element.ALIGN_CENTER, -3f);

    LineSeparator line2 = new LineSeparator(1f, 95, new BaseColor(238, 238, 238), Element.ALIGN_CENTER, -2f);


    public PrescriptionFileMdwkService() throws IOException, DocumentException {
    }

    /**
     * 生成PDF文件
     *
     * @param path
     *
     * @throws IOException
     * @throws DocumentException
     */
    public void generatePDF(String path, PrescriptionInfoVO prescriptionInfo) throws IOException, DocumentException {
        long start = System.currentTimeMillis();
        File file = new File(path);
        FileUtils.forceMkdirParent(file);
        FileOutputStream fos = new FileOutputStream(path);
        this.generatePDF(fos, prescriptionInfo);
        fos.close();
        LOGGER.info("处方PDF生成完成 cost:{}ms, serialNumber:{}, path:{}", System.currentTimeMillis() - start, prescriptionInfo.getSerialNumber(), path);
    }

    /**
     * 生成PNG图片
     *
     * @param path
     *
     * @throws IOException
     * @throws DocumentException
     */
    public void generateImg(String path, PrescriptionInfoVO prescriptionInfo) throws IOException, DocumentException {
        long start = System.currentTimeMillis();
        File file = new File(path);
        FileUtils.forceMkdirParent(file);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        this.generatePDF(baos, prescriptionInfo);
        PDDocument pdDocument = PDDocument.load(baos.toByteArray());
        PDFRenderer pdfRenderer = new PDFRenderer(pdDocument);
        BufferedImage image = pdfRenderer.renderImageWithDPI(0, 150, ImageType.RGB);
        ImageIO.write(image, "PNG", new File(path));
        pdDocument.close();
        baos.close();
        LOGGER.info("处方PNG生成完成 cost:{}ms serialNumber:{}, path:{}", System.currentTimeMillis() - start, prescriptionInfo.getSerialNumber(), path);
    }


    private void generatePDF(OutputStream ouput, PrescriptionInfoVO prescriptionInfo) throws DocumentException, IOException {

        // 页面大小
        Rectangle rect = new Rectangle(PageSize.A4);
        Document document = new Document(rect);
        // 创建PdfWriter对象
        PdfWriter writer = PdfWriter.getInstance(document, ouput);
        // 打开文档
        document.open();
        // 页边空白
        document.setMargins(20, 20, 30, 40);

        // 设置医院图章
        File file = new File(HOSPITAL_SEAL_PATH);
        if (file.exists()) {
            Image image = Image.getInstance(HOSPITAL_SEAL_PATH);
            image.setAbsolutePosition(400, 20);
            image.scaleToFit(150, 150);
            document.add(image);
        } else {
            LOGGER.warn("互联网医院处方图章不存在，请检查图章文件目录 {}", HOSPITAL_SEAL_PATH);
        }

        // 处方签名
        this.addImage(document, prescriptionInfo.getDoctorSignImg(), 130, 130, 50, 50);
        this.addImage(document, prescriptionInfo.getPrePharmacistSignImg(), 150, 90, 50, 50);
        this.addImage(document, prescriptionInfo.getPharmacistSignImg(), 330, 90, 50, 50);

        // title
        Paragraph titleRow = new Paragraph(prescriptionInfo.getHospitalName() + "处方笺", firsetTitleFont);
        titleRow.setAlignment(PdfContentByte.ALIGN_CENTER);
        titleRow.setSpacingAfter(20);
        document.add(titleRow);

        // 编号
        Paragraph snRow = new Paragraph("编号：" + prescriptionInfo.getSerialNumber(), fontContent);
        snRow.setAlignment(PdfContentByte.ALIGN_CENTER);
        snRow.setSpacingAfter(5);
        document.add(snRow);

        // 分割线
        Paragraph lineParagraph = new Paragraph();
        lineParagraph.add(line);
        lineParagraph.setSpacingAfter(20);
        document.add(lineParagraph);

        // 患者信息
        String genderStr = prescriptionInfo.getPatientGender() == 0 ? "女" : "男";
        Phrase patientNamePhrase = this.buildPhrase("姓名：", prescriptionInfo.getPatientName(), fontContent, fontContent);
        Phrase patientGenderPhrase = this.buildPhrase("性别：", genderStr, fontContent, fontContent);
        Phrase patientAgePhrase = this.buildPhrase("年龄：", prescriptionInfo.getPatientAge() + prescriptionInfo.getPatientAgeUnit(), fontContent,
                fontContent);
        document.add(this.buildTable(new float[]{ 0.3f, 0.3f, 0.3f }, 95, 0, 0, patientNamePhrase, patientGenderPhrase, patientAgePhrase));

        // 就诊信息
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm");
        String prescriptionTime = dateFormat.format(prescriptionInfo.getCreatedAt());
        Phrase time = this.buildPhrase("时间：", prescriptionTime, fontContent, fontContentEn);
        document.add(this.buildTable(new float[]{ 1f }, 95, 0, 0, time));

        Phrase department = this.buildPhrase("科室：", prescriptionInfo.getDepartmentName(), fontContent, fontContent);
        document.add(this.buildTable(new float[]{ 1f }, 95, 0, 0, department));

        Phrase diagnosis = this.buildPhrase("临床诊断：", prescriptionInfo.getDiagnosis(), fontContent, fontContent);
        document.add(this.buildTable(new float[]{ 1f }, 95, 0, 0, diagnosis));

        document.add(line);

        // 第七行-RP
        Paragraph rp = new Paragraph("Rp", secondTitleFontEn);
        rp.setSpacingBefore(20);
        rp.setIndentationLeft(15);
        document.add(rp);

        // 药品列表
        for (int i = 0; i < MAX_SKU_QUANTITY; i++) {
            List<PrescriptionSkuVO> skus = prescriptionInfo.getSkus();
            if (skus.size() > i) {
                PrescriptionSkuVO skuObj = skus.get(i);
                // {药品名称}  X{数量}
                Phrase sku = this.buildPhrase(i + 1 + "." + skuObj.getName(), " ", fontContentBOLD, fontContentBOLD);
                Phrase quantity = this.buildPhrase("X ", skuObj.getQuantity() + "", fontContentBOLD, fontContentBOLD);
                document.add(this.buildTable(new float[]{ 0.9f, 0.1f }, 90, 20, 0, sku, quantity));

                // 用法用量
                Paragraph useges = new Paragraph("用法：" + skuObj.getUseges() + " " + skuObj.getBackup(), fontContent2);
                useges.setIndentationLeft(28);
                document.add(useges);

            } else {
                // 占位
                Phrase sku = this.buildPhrase(" ", " ", fontContent, fontContent);
                Phrase quantity = this.buildPhrase(" ", " ", fontContent, fontContent);
                document.add(this.buildTable(new float[]{ 0.9f, 0.1f }, 90, 20, 0, sku, quantity));
                Paragraph useges = new Paragraph(" ", fontContent2);
                useges.setIndentationLeft(28);
                document.add(useges);
            }


        }

        // 换行
        document.add(Chunk.NEWLINE);

        // 页脚
        Paragraph lineParagraph1 = new Paragraph(" ");
        lineParagraph1.setSpacingAfter(180);
        document.add(lineParagraph1);

        document.add(line);

        Phrase dr = this.buildPhrase("医生：", prescriptionInfo.getDoctorName(), fontContent, fontContent);
        PdfPTable pdfPTable1 = this.buildTable(new float[]{ 1f }, 95, 5, 0, dr);
        document.add(pdfPTable1);

        document.add(Chunk.NEWLINE);

        document.add(new Paragraph(" "));
        String prePharmacistName = StringUtils.isBlank(prescriptionInfo.getPrePharmacistName()) ? " " : prescriptionInfo.getPrePharmacistName();
        String pharmacistName = StringUtils.isBlank(prescriptionInfo.getPharmacistName()) ? " " : prescriptionInfo.getPharmacistName();
        Phrase pharmacist = this.buildPhrase("审核调配：", prePharmacistName, fontContent, fontContent);
        Phrase check = this.buildPhrase("核对发药：", pharmacistName, fontContent, fontContent);
        PdfPTable table2 = this.buildTable(new float[]{ 0.35f, 0.65f }, 95, 0, 0, pharmacist, check);
        document.add(table2);
        document.add(Chunk.NEWLINE);

        document.add(line);

        Paragraph tips = new Paragraph("注意：为确保用药安全，处方有效日为当日有效。", fontContent2);
        tips.setIndentationLeft(16);
        document.add(tips);

        document.close();
    }


    private Phrase buildPhrase(String title, String content, Font titleFont, Font contentFont) {
        Phrase phrase = new Phrase();
        Chunk chunkTitle = new Chunk(title, titleFont);
        Chunk chunkContent = new Chunk(content, contentFont);
        phrase.add(chunkTitle);
        phrase.add(chunkContent);
        return phrase;
    }


    private PdfPCell buildCell(Phrase phrase) {
        PdfPCell pdfPCell = new PdfPCell(phrase);
        pdfPCell.disableBorderSide(Rectangle.TOP); // 隐藏单元格周边的上边框
        pdfPCell.disableBorderSide(Rectangle.BOTTOM);// 隐藏单元格周边的下边框
        pdfPCell.disableBorderSide(Rectangle.LEFT); // 隐藏单元格周边的左边框
        pdfPCell.disableBorderSide(Rectangle.RIGHT);// 隐藏单元格周边的右框
        return pdfPCell;
    }


    private PdfPTable buildTable(float[] relativeWidths, int widthPercentage, int pacingBefore, int pacingAfter,
                                 Phrase... phrases) {
        PdfPTable pdfPTable = new PdfPTable(relativeWidths);
        pdfPTable.setWidthPercentage(widthPercentage);
        for (Phrase phrase : phrases) {
            pdfPTable.addCell(this.buildCell(phrase));
        }
        pdfPTable.setSpacingBefore(pacingBefore);
        pdfPTable.setSpacingAfter(pacingAfter);
        return pdfPTable;
    }

    private void addImage(Document document, String path, int x, int y, int fitW, int fitH) throws IOException, DocumentException {
        if (StringUtils.isBlank(path)) {
            return;
        }
        File file = new File(path);
        if (file.exists()) {
            Image image = Image.getInstance(path);
            image.setAbsolutePosition(x, y);
            image.scaleToFit(fitW, fitH);
            document.add(image);
        }
    }

}
